package com.aluka.nirvana.framework.security.provider;

import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.InternalAuthenticationServiceException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

/**
 * 登录认证默认实现
 * @author gongli
 * @since 2019/4/10 13:40
 */
@Slf4j
public class DefaultAuthenticationProvider implements AuthenticationProvider {

    @Autowired(required = false)
    private UserDetailsService userDetailsService;

    /**
     * 默认登录逻辑
     * @param authentication 登录信息
     * @return UsernamePasswordAuthenticationToken 登录令牌
     */
    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = (String) authentication.getPrincipal();
        String password = (String) authentication.getCredentials();
        log.info("登录账户: {}/{}" ,username ,password);

        if(userDetailsService == null){
            throw new InternalAuthenticationServiceException("请创建["+UserDetailsService.class+"]的具体实现类，用于获取用户信息");
        }
        UserDetails userInfo = userDetailsService.loadUserByUsername(username);

        //判断密码是否正确
        if(!new BCryptPasswordEncoder().matches(password,userInfo.getPassword())){
            throw new BadCredentialsException("密码不正确");
        }

        return new UsernamePasswordAuthenticationToken(userInfo,password,userInfo.getAuthorities());
    }

    @Override
    public boolean supports(Class<?> authentication) {
        return true;
    }
}
